<!--
 * @ Author: yangzhiwei
 * @ Create Time: 2021-04-15 09:34:23
 * @ Modified by: yangzhiwei
 * @ Modified time: 2021-04-15 15:15:56
 * @ Description: 下拉刷新组件
 -->
<template>
  <div
    class="refresh"
    :style="style"
    @touchstart="touchStart($event)"
    @touchmove="touchMove($event)"
    @touchend="touchEnd($event)"
  >
    <!-- 下拉刷新顶部 -->
    <div class="refresh_head">
      <p>{{ refreshText }}</p>
    </div>
    <!-- 内容插槽 -->
    <slot></slot>
    <!-- 底部上拉加载loading -->
    <div class="loading">
      {{ loadingText }}
    </div>
  </div>
</template>
<script lang="ts">
/**
 * 定义data的接口类型
 */
interface global {
  pageY: number;
  duration: number;
  moveDistance: number;
  scrollPosition: number;
  loadingText: string;
  moveState: number;
  notMores: boolean;
}
/**
 * 定义props的接口类型
 */
interface popType {
    distanceBottom: number
}
import {
  computed,
  defineComponent,
  onBeforeUnmount,
  nextTick,
  onMounted,
  reactive,
  toRefs,
} from "vue";
export default defineComponent({
  props: {
    distanceBottom: {
      type: Number,
      default: 10,
    },
  },
  setup(props: popType, { emit }) {
    const dataRow: global = reactive({
      pageY: 0,
      duration: 0, //动画持续时间，0就是没有动画
      moveState: 0, //开始滑动到结束后状态的变化 0:下拉即可刷新 1:释放即可刷新 2:加载中
      moveDistance: 0,
      scrollPosition: 0,
      loadingText: "加载中...",
      notMores: false,
    });
    const touchStart = (e: any) => {
      dataRow.duration = 0; // 关闭动画
      dataRow.moveState = 0; //状态归0
      dataRow.moveDistance = 0; // 滑动距离归0
      dataRow.pageY = e.targetTouches[0].pageY;
    };
    const touchMove = (e: any) => {
      let scrollTop: number =
        document.documentElement.scrollTop || document.body.scrollTop;
      //首先判断我们有没有滚动条，如果有，我们下拉刷新就不能启用。
      if (scrollTop > 0) return;
      let move: number = e.targetTouches[0].clientY - dataRow.pageY;
      //判断手指滑动的距离，只有为正数才代表用户下拉了。
      if (move > 0) {
        e.preventDefault(); //阻止默认事件
        //增加滑动阻力的感觉
        dataRow.moveDistance = Math.pow(move, 0.8);
        if (dataRow.moveDistance > 50) {
          //如果滑动距离大于50 那我就告诉你，释放即可刷新
          if (dataRow.moveState === 1) return;
          dataRow.moveState = 1;
        } else {
          //否则 恢复原样
          if (dataRow.moveState === 0) return;
          dataRow.moveState = 0;
        }
      }
    };
    const touchEnd = () => {
      dataRow.duration = 300;
      if (dataRow.moveDistance > 50) {
        //这里逻辑跟touchMove一样，但是需要真的加载数据了，那moveState变为2 所以加载动画在这出现
        dataRow.moveState = 2;
        //因为还没加载完，我得让加载动画显示着，所以这里移动距离为50
        dataRow.moveDistance = 50;
        emit("refreshOver");
      } else {
        //否则 给我老老实实恢复原样
        dataRow.moveDistance = 0;
      }
      //重置上拉加载状态
      resetRefresh()
    };
    const style = computed(() => {
      return {
        transition: `${dataRow.duration}ms`,
        transform: `translate3d(0,${dataRow.moveDistance}px, 0)`,
      };
    });
    /**
     * 结束下拉刷新
     */
    const refreshOver = () => {
      dataRow.moveDistance = 0;
    };
    /**
     * 下拉显示文本
     */
    const refreshText = computed(() => {
      let status: number | string = dataRow.moveState;
      let text: string | null = "";
      if (status == 0) {
        text = "下拉刷新";
      } else if (status == 1) {
        text = "刷新中...";
      } else if (status == 2) {
        text = "刷新成功";
      }
      return text;
    });
    /**
     * 监听页面滚动
     */
    const handleScroll = () => {
      // 获取页面滚动的位置
      const scrollTop: number =
        document.documentElement.scrollTop || document.body.scrollTop;
      // 获取页面整体的高度
      const windowHeight: number =
        document.documentElement.clientHeight || document.body.clientHeight;
      // 获取滚动区域的高度
      const scrollHeight: number =
        document.documentElement.scrollHeight || document.body.scrollHeight;
      // 如果页面滚动的位置 + 页面整体的高度 大于等于 滚动后区域的高度减去 设定的距离底部的距离
      if (scrollTop + windowHeight >= scrollHeight - props.distanceBottom) {
        //   说明触底了
        if (dataRow.notMores) {
          // 如果已经禁用了刷新，这时就不做任何操作，避免多余请求消耗性能
          return;
        }
        //传递事件加载更多
        emit('getMore')
      }
    };
    /**
     * 上拉加载没有更多数据了
     * 这时候禁用刷新
     */
    const notMore = () => {
      dataRow.notMores = true;
      dataRow.loadingText = "没有更多了...";
    };
    /**
     * 启用刷新功能
     * 用于tab切换时
     */
    const resetRefresh = () => {
      dataRow.notMores = false;
      dataRow.loadingText = "加载中...";
    };
    onMounted(() => {
      nextTick(() => {
        /***
         * 添加页面滚动事件监听
         */
        window.addEventListener("scroll", handleScroll);
      });
    });
    onBeforeUnmount(() => {
      /**页面销毁时 移除监听事件 */
      window.removeEventListener("scroll", handleScroll);
    });
    return {
      ...toRefs(dataRow),
      touchStart,
      touchMove,
      touchEnd,
      style,
      refreshOver,
      refreshText,
      handleScroll,
      notMore,
      resetRefresh,
    };
  },
});
</script>
<style lang="scss" scoped>
.refresh {
  height: 100%;
  position: relative;
  .refresh_head {
    position: absolute;
    left: 50%;
    top: -0.746667rem;
    transform: translateX(-50%);
    font-size: 0.32rem;
    color: #666;
    text-align: center;
  }
  .loading {
    text-align: center;
    color: #666;
    font-size: 0.32rem;
    padding: 0.266667rem 0.266667rem 0.4rem;
  }
}
</style>
